/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package config;

import beans.PedidoBD;
import beans.Carro;
import beans.HoraExtra;
import beans.Incidencia;
import beans.Mapa;
import beans.Moto;
import beans.Path;
import beans.Pedido;
import beans.Punto; 
import beans.Vehiculo;
import colonia.Nodo;
import java.util.ArrayList;
import org.json.simple.*;
import packetTracker.Dispatcher;
import packetTracker.PacketTracker;

/**
 *
 * @author Shadow
 */
public class GestorVehiculos {
    
    private static GestorVehiculos _instancia;
    private ArrayList<Vehiculo> _vehiculos = new ArrayList<>();
    private ArrayList<PedidoBD> _pedidosBD = new ArrayList<>();
    private ArrayList<Incidencia> _incidencias = new ArrayList<>();
    private ArrayList<Incidencia> _incidenciasActuales = new ArrayList<>();
    private ArrayList<HoraExtra> _horasExtras = new ArrayList<>();

    public ArrayList<HoraExtra> getHorasExtras() {
        return _horasExtras;
    }

    public void setHorasExtras(ArrayList<HoraExtra> _horasExtras) {
        this._horasExtras = _horasExtras;
    }
    
    
    private boolean encontrado=false;
    
    private void limpiaIncidencias(Vehiculo v){
        for (int i = 0; i < _incidenciasActuales.size(); i++){
            if (_incidenciasActuales.get(i).getVehiculo() == v){
                _incidenciasActuales.remove(i);
                return;
            }
        }
    }
    
    public void restauraVehiculos (){
        for (Vehiculo vehiculo:_vehiculos){
            if (!vehiculo.isDisponible()){
                limpiaIncidencias(vehiculo);
                vehiculo.setDisponible(true);
                vehiculo.setPosicionActual(vehiculo.getPosicionInicial());
            }
        }
    }
    public String getJson(int idCarro, int idPedido, int idCliente){ 
        
        if (idCarro != -1) idCarro--;
        int tamRutaMostrado = 100; // sera parametro
        ArrayList<Pedido> pedidosMapa = new ArrayList<>();
        String hora = Reloj.getInstancia().getFechaString("HH:mm");
        String fecha = Reloj.getInstancia().getFechaString("dd-MM-yyyy");
        JSONObject obj = new JSONObject();
        JSONArray vehiculosJson = new JSONArray();
        int tam = this._vehiculos.size();
        for(int i =0; i < tam ; i++){ 
            JSONObject v = new JSONObject();
            JSONArray ruta = new JSONArray(); 
            Path listaRuta = this._vehiculos.get(i).getRuta(); 
            int tamRuta = listaRuta.size();
            for(int j =0; j < (tamRuta < tamRutaMostrado? tamRuta : tamRutaMostrado);j++){
                JSONObject punto = new JSONObject(); 
                punto.put("x", listaRuta.get(j).getX());
                punto.put("y", listaRuta.get(j).getY());
                ruta.add(punto);
            }
            v.put("ruta",ruta);
            ArrayList<Pedido> listaPedidos = (ArrayList<Pedido>)this._vehiculos.get(i).getListaPedido().clone();
            v.put("x",this._vehiculos.get(i).getPosicionActual().getX());
            v.put("y",this._vehiculos.get(i).getPosicionActual().getY());
            v.put("placa", this._vehiculos.get(i).getPlaca());
            v.put("tipo",this._vehiculos.get(i).getTipoVehiculo());
            if (((i == idCarro) || (idCarro==-1)) && (idPedido==-1) && (idCliente==-1)){
                 vehiculosJson.add(v);
                 pedidosMapa.addAll(listaPedidos);
            }
            if ((idPedido!=-1)&& (idCarro==-1) && (idCliente==-1)){
               for (int j=0; j<this._vehiculos.get(i).getListaPedido().size();j++){
                   if ((idPedido==this._vehiculos.get(i).getListaPedido().get(j).getIdPedido()) && ("Pendiente".equals(this._vehiculos.get(i).getListaPedido().get(j).getEstadoPedido()))){
                       vehiculosJson.add(v);
                       pedidosMapa.addAll(listaPedidos);
                       encontrado=true;
                   }
               }
               if (encontrado==false) {
                   //Mostrar mensaje de que pedido ya fue entregado
               }
              
           } 
            JSONArray pedidos = new JSONArray();
            int tamPedido = listaPedidos.size();
            for(int j =0; j < tamPedido;j++){
                JSONObject pedido = new JSONObject(); 
                pedido.put("x", listaPedidos.get(j).getDestino().getX());
                pedido.put("y", listaPedidos.get(j).getDestino().getY());
                pedido.put("cp", listaPedidos.get(j).getDemanda());
                long minRest = (listaPedidos.get(j).getFechaVencimiento().getTimeInMillis()-Reloj.getInstancia().getFecha().getTimeInMillis())/60000;
                pedido.put("minutosRestantes",minRest);
		pedido.put("idPedido", listaPedidos.get(j).getIdPedido());
                //PedidoBD pdBD = new PedidoBD(listaPedidos.get(j).getIdPedido());
                _pedidosBD = (ArrayList<PedidoBD>) Dispatcher.getPedidosBD().clone();
                //int index  = _pedidosBD.indexOf(listaPedidos.get(j));
                boolean encontradoB = false;
                int index = -1;
                while(!encontradoB){
                    index++;
                    if(_pedidosBD.get(index).getIdPedido() == listaPedidos.get(j).getIdPedido())
                        encontradoB = true;
                }
                if(encontradoB){
                    _pedidosBD.get(index).setMinRest(minRest);
                    _pedidosBD.get(index).setEstado(2);
                }
               /*if (_vehiculos.get(i))
                */
                pedidos.add(pedido);
            }
            v.put("pedidos",pedidos);       
            
        }
        obj.put("vehiculos", vehiculosJson);
        obj.put("diasSimulados", Parameters._diasSimulados);
        obj.put("reloj",hora);
        obj.put("fecha",fecha);
        JSONArray pedidosJson = new JSONArray();
        for(int i =0;i< pedidosMapa.size();i++){
            JSONObject pedido = new JSONObject();
            pedido.put("x", pedidosMapa.get(i).getDestino().getX());
            pedido.put("y", pedidosMapa.get(i).getDestino().getY());
            pedido.put("cp",pedidosMapa.get(i).getDemanda());
            pedido.put("idPedido", pedidosMapa.get(i).getIdPedido());
            pedidosJson.add(pedido);
        }
        obj.put("pedidos", pedidosJson);
        
        JSONArray incidenciasJSON = new JSONArray();
        for(int i =0;i< _incidenciasActuales.size();i++){
            JSONObject incidencia = new JSONObject();
            incidencia.put("x", _incidenciasActuales.get(i).getLocation().getX());
            incidencia.put("y", _incidenciasActuales.get(i).getLocation().getY());
            incidenciasJSON.add(incidencia);
        }
        obj.put("incidencias", incidenciasJSON);
        //bloqueo
        JSONArray bloqueosJson = new JSONArray();
        for(int i =0;i< Parameters.getListaBloqueo().size();i++){
            JSONObject punto = new JSONObject();
            punto.put("x", Parameters.getListaBloqueo().get(i).getX());
            punto.put("y", Parameters.getListaBloqueo().get(i).getY());               
            bloqueosJson.add(punto);            
        }
        
        obj.put("bloqueos", bloqueosJson);
        return obj.toJSONString();
    }
    

    public ArrayList<Vehiculo> getVehiculos() {
        return _vehiculos;
    }
    
    public static GestorVehiculos getInstancia(){
        if (_instancia == null) 
            _instancia = new GestorVehiculos();
        return _instancia;
    }
    
    private GestorVehiculos(){
    }
    
    public void crearVehiculos (){
        int i = 1;
        int contMoto = 0;
        int contCarro = 0;
        String nplaca;
        Vehiculo vehiculo = null;
        for (; i <= Parameters.getNumCarros()+Parameters.getNumMotos(); i++){
            if (i <= Parameters.getNumMotos()){
                vehiculo = new Moto();
                vehiculo.setId(i);
                this._vehiculos.add(vehiculo);
                nplaca = "" + i;
                if (i<10){
                    nplaca = 0 + nplaca;
                }
                vehiculo.setPlaca(nplaca);
            }
            if (i <= Parameters.getNumMotos()+Parameters.getNumCarros() && i > Parameters.getNumMotos()){
                vehiculo = new Carro();
                vehiculo.setId(i);
                this._vehiculos.add(vehiculo);
                nplaca = "" + i;
                if (i<10){
                    nplaca = 0 + nplaca;
                }
                vehiculo.setPlaca(nplaca);
            }
        }
      for (int j=0;j < _vehiculos.size();j++){
        this._vehiculos.get(j).setPlaca("XXX-0" + this._vehiculos.get(j).getPlaca());
        }  
    }
     
    
    public Vehiculo getVehiculo(int index){
        return _vehiculos.get(index);
    }
    public void asignarRutas(ArrayList<ArrayList<Nodo>> bestRoutes,ArrayList<ArrayList<Pedido>> pedidosAsignados){
        for(int i=0;i<bestRoutes.size();i++){
            ArrayList<Punto> ruta = new ArrayList<>();
            ArrayList<Nodo> solucion = bestRoutes.get(i);
            if (solucion == null) continue;
            for(int j=1;j< solucion.size();j++){
                Punto p1 = solucion.get(j-1).getPunto();
                Punto p2 = solucion.get(j).getPunto();
                ArrayList<Punto> segment = GestorVehiculos.Astar(p1,p2);

                if(j!=1)segment.remove(segment.get(0));
                ruta.addAll(segment);
            }
            if (ruta.isEmpty() || solucion.size()==1)
                this._vehiculos.get(i).setRuta(solucion.get(0).getPunto());
            else
                this._vehiculos.get(i).setRuta(ruta);
            this._vehiculos.get(i).setListaPedido(pedidosAsignados.get(i));
        }
    }
    
    public void actualizarVehiculosYOrdenes(int tiempo,ArrayList<Pedido> ordenes){
        int size = this._vehiculos.size();
        for(int i=0;i<size;i++){
            this._vehiculos.get(i).avanzar(tiempo,ordenes);
        }
    }
    
    public static float geomDistance(Punto p1, Punto p2){
        int x1 = p1.getX();
        int x2 = p2.getX();
        int y1 = p1.getY();
        int y2 = p2.getY();
        return (float) Math.sqrt((x1-x2)*(x1-x2) +(y1-y2)*(y1-y2));
    }

    private static ArrayList<Punto> getCheapestRoute(ArrayList<ArrayList<Punto>> routes, Punto p) {
        ArrayList<Punto> cheapest = null;
        float minCost = Float.POSITIVE_INFINITY;
        for(int i=0;i<routes.size();i++){
            ArrayList<Punto> current = routes.get(i);
            //añadir el costo de las aristas en caso se necesite aristas de difernte peso
            float cost = geomDistance(current.get(current.size()-1),p);
            if(cost <= minCost){
                minCost = cost;
                cheapest = current;
            }
        }
        routes.remove(cheapest);
        return cheapest;
    }
        
    public static ArrayList<Punto> Astar(Punto p1, Punto p2){
        ArrayList<ArrayList<Punto>> routes = new ArrayList<ArrayList<Punto>>();
        ArrayList<Punto> visitados = new ArrayList<Punto>();
        //inicializar una ruta con el nodo inicial
        ArrayList<Punto> route = new ArrayList<Punto>();
        route.add(p1);
        routes.add(route);
        
        while(visitados.size() != Mapa.size()){
            ArrayList<Punto> cheapest = getCheapestRoute(routes,p2);
            Punto ultimo = cheapest.get(cheapest.size()-1);
            if(ultimo == p2)return cheapest;
            for(int i=0;i < ultimo.getnAdj();i++){
                if(!ultimo.getAdj()[i].estaBloqueado() && !visitados.contains(ultimo.getAdj()[i])){
                    ArrayList<Punto> nuevaRuta = (ArrayList<Punto>)cheapest.clone();
                    nuevaRuta.add(ultimo.getAdj()[i]);
                    routes.add(nuevaRuta);
                }
            }
            visitados.add(ultimo);
        }
        return null;
    }
    public void actualizaTurno() {
        for (int i=0;i<_vehiculos.size();i++){
            _vehiculos.get(i).setTurno(Reloj.getInstancia().obtenerTurno(Reloj.getInstancia().getHora()));
            _vehiculos.get(i).setFinTurno(Reloj.getInstancia().obtenerFinTurno());
        }        
    }

    public ArrayList<Incidencia> getIncidencias() {
        return _incidencias;
    }

    public void setIncidencias(ArrayList<Incidencia> _incidencias) {
        this._incidencias = _incidencias;
    }

    public ArrayList<Incidencia> getIncidenciasActuales() {
        return _incidenciasActuales;
    }

    public void setIncidenciasActuales(ArrayList<Incidencia> _incidenciasActuales) {
        this._incidenciasActuales = _incidenciasActuales;
    }
    
}
